
//题目的数据模型





/***
 * 选项
 */
export class Option {
    id;     //选项的标识符，在一个题目中，需要唯一
    content;    //选项的内容
    choiceQuestion;     //选择所属的题目
    selected;   //是否选中


    /**
     * 构造函数
     * @param content : any     选项的内容
     * @param id : any     选项的标识符，在一个题目中，需要唯一
     * @param choiceQuestion : ChoiceQuestion   选择所属的题目
     */
    constructor(content, id, choiceQuestion) {
        this.content = content;
        this.id = id;
        this.choiceQuestion = choiceQuestion;
    }


}







/***
 * 选择约束类
 */
export class ChoiceCondition {

    _minSelectCount = 0;    //最小选择数目
    _maxSelectCount = 1;    //最大选择数目

    /**
     * 构造函数
     * @param minSelectCount : number     最小选择数目
     * @param maxSelectCount : number     最大选择数目
     */
    constructor(minSelectCount, maxSelectCount) {
        this.minSelectCount = minSelectCount;
        this.maxSelectCount = maxSelectCount;
    }


    /* 
    @property @计算 @读写 minSelectCount : number   最小选择数目
    */
    get minSelectCount() {
        return this._minSelectCount;
    }

    set minSelectCount(value) {
        if (value > this._maxSelectCount) {
            tihs._maxSelectCount = value;
        }

        this._minSelectCount = value;
    }



    /* 
    @property @计算 @读写 maxSelectCount : number   最大选择数目
    */
    get maxSelectCount() {
        return this._maxSelectCount;
    }
    set maxSelectCount(value) {
        if (value < this._minSelectCount) {
            tihs._minSelectCount = value;
        }

        this._maxSelectCount = value;
    }



    /* 
    @property @计算 @只读 requisite : boolean   是否必须选择
    */
    get requisite() {
        return this.minSelectCount > 0;
    }

    /* 
    @property @计算 @只读 multiselect : boolean   是否多选
    */
    get multiselect() {
        return this.maxSelectCount == 1;
    }

}










/***
 * 选择题
 */
export class ChoiceQuestion extends ChoiceCondition {



    type;   //题目类型
    id;     //题目的唯一标识符
    subject;    //选择题的问题、标题；
    _options;    //盛装选择题的所有选项的数组
    rightAnswerIds;    //盛装正确答案id的数组
    _defaultSelectedIds;    //盛装默认选中的答案id的数组
    scoreValuel;    //题目的分值
    





    /**
     * 构造函数
     * @param subject : any     选择题的问题、标题；
     * @param minSelectCount : number 最小选择数目
     * @param maxSelectCount : number 最大选择数目
     * @param id : any   题目的唯一标识符
     * @param options : Array<Option> = []  盛装选择题的所有选项的数组
     * @param rightAnswerIds : Array = []  盛装正确答案id的数组
     * @param defaultSelectedIds : Array = []  盛装默认选中的答案id的数组
     * @param scoreValuel : number = 1    题目的分值
     * @param type : any    题目类型
     */
    constructor(subject, minSelectCount, maxSelectCount,id, options = [], rightAnswerIds = [],defaultSelectedIds = [], scoreValuel = 1, type) {
        super(minSelectCount, maxSelectCount);

        this.subject = subject;
        this.options = options;
        this.id = id;
        this.type = type;
        this.rightAnswerIds = rightAnswerIds;
        this.defaultSelectedIds = defaultSelectedIds;
        this.scoreValuel = scoreValuel;

    }



    /* 
    @property @计算 @读写 options : [Option]   盛装选择题的所有选项的数组
    */
    get options() {
        return this._options;
    }
    set options(value) {
        if (value && value.length > 0) {
            value.forEach(function (element) {
                element.choiceQuestion = this;
            }, this);
        }

        this._options = value;
    }




    /* 
    @property @计算 @读写 defaultSelectedIds : Array   默认选中的选项的id数组
    */
    get defaultSelectedIds(){
        return this._defaultSelectedIds;
    }

    set defaultSelectedIds(value){
        this.defaultSelectedIds.forEach(function(optionID){
            this.selectOptionOfId(optionID);
        },this);
        this._defaultSelectedIds = value;
    }


    /* 
    @property @计算 @只读 selectedOptions : [Option]   获得所有被选中的选项
    */
    get selectedOptions() {
        return this.options.filter(function (option, index) {
            return option.selected;
        });
    }


    /* 
    @property @计算 @只读 selectedOptionIds : Array   获得所有被选中的选项的id
    */
    get selectedOptionIds() {
        return this.selectedOptions.map(function(option){
            return option.id
        });
    }



   
    /* 
    @property @计算 @只读 score : number  回答本题得的分数
    */
    get score(){
        return this.testAnswer() ? this.scoreValuel : 0;
    }


    /**
     * 选中 id 为 optionID 的选项
     * @param optionID : any  需要被选中的选项的id
     */
    selectOptionOfId(optionID){
        this.options.forEach(function(option){
            if (option.id === optionID){
                option.selected = true;
            }
        });
    }


    /**
     * 选中 idList 中指定的所有 选项
     * @param idList : Array  需要被选中的选项的id数组
     */
    selectOptionsOfIdList(idList){
        this.options.forEach(function(option){
            if (idList.includes(option.id)){
                option.selected = true;
            }
        });
    }




    /**
     * 只选中 idList 中指定的所有 选项
     * @param idList : Array  需要被选中的选项的id数组
     */
    onlySelectOptionsOfIdList(idList){
        this.options.forEach(function(option){
            if (idList.includes(option.id)){
                option.selected = true;
            }else{
                option.selected = false;
            }
        });
    }


    /**
     * 只选中除 idList 中指定的 之外的 所有选项
     * @param idList : Array  需要被排除选中的选项的id数组
     */
    onlySelectOptionsOutofIdList(idList){
        this.options.forEach(function(option){
            if (idList.includes(option.id)){
                option.selected = false;
            }else{
                option.selected = true;
            }
        });
    }



    /**
     * 取消选中 id 为 optionID 的选项
     * @param optionID : any  需要被取消选中的选项的id
     */
    deselectOptionOfId(optionID){
        this.options.forEach(function(option){
            if (option.id === optionID){
                option.selected = false;
            }
        });
    }




    /**
     * 取消选中 idList 中指定的所有 选项
     * @param idList : Array  需要被取消选中的选项的id数组
     */
    deselectOptionsOfIdList(idList){
        this.options.forEach(function(option){
            if (idList.includes(option.id)){
                option.selected = false;
            }
        });
    }




    


    /**
     * 取消所有选项的选中
     */
    deselectAll(){
        this.options.forEach(function(option){
            option.selected = false;
        });
    }


    /**
     * 重围选中，重置后只选中默认选中的选项
     */
    resetSelect(){
        this.onlySelectOptionsOfIdList(this.defaultSelectedIds);
    }



    //测试是否满足必须
    testRequisite() {
        return !(this.requisite) || this.selectedOptions.length > 0;
    }


    //测试是否满足最小选择数
    testMinSelectCount() {
        return this.selectedOptions.length >= this.minSelectCount;
    }

    //测试是否满足最大选择数
    testMaxSelectCount() {
        return this.selectedOptions.length <= this.maxSelectCount;
    }

    //测试是否满足所有的约束条件
    testAllCondition() {
        return this.testRequisite() && this.testMinSelectCount() && this.testMaxSelectCount();
    }


    //测试是否回答正确，需要设置 rightAnswerIds
    testAnswer() {

        let selectedIDs = this.selectedOptions.map(function (option) {
            return option.id;
        });

        let rightIDs = this.rightAnswerIds;

        let selectedsIsAllRight = this.selectedIDs.every(function (seleId) {

            let haveId = rightIDs.includes(seleId);

            rightIDs = rightIDs.filter(function (rightId) {
                return rightId !== seleId;
            });

            return haveId;
        });


        let rightIsAllSelected = rightIDs.length == 0;



        return selectedsIsAllRight && rightIsAllSelected;

    }



    /**
     * 返回 id 为 optionID 的 选项 在 options 中的索引；如果没有符合条件的元素返回 -1
     * @param optionID : any 被查找的选项的id
     */
    findIndexForId(optionID){
        return this.options.findIndex(function(option){
            return option.id === optionID;
        });
    }


    /**
     * 返回 id 为 optionID 的 选项 ；如果没有符合条件的元素返回 undefined
     * @param optionID : any 被查找的选项的id
     */
    findOptionForId(optionID){
        return this.options.find(function(option){
            return option.id === optionID;
        });
    }



    /**
     * 返回 idList 中的 id 对应的 选项 在 options 中的索引的数组；
     * @param idList : Array 被查找的选项的id列表
     */
    findIndexListForIdList(idList){
        let optionList = this.findOptionListForIdList(idList);
        return this._getOptionIds(optionList);
    }


    /**
     * 返回 idList 中的 id 对应的 选项 的数组；
     * @param idList : Array 被查找的选项的id列表
     */
    findOptionListForIdList(idList){
        return this.options.filter(function(option){
            return idList.includes(option.id);
        });
    }


    /**
     * 删除 id 为 optionID 的 选项 ；
     * @param optionID : any 被删除的选项的id
     */
    deleteOptionForId(optionID){
        this.options.forEach(function(option, index, arr){
            if (option.id === optionID){
                arr.splice(index,1);
            }
        });
    }



    /**
     * 删除 idList 中指定的所有选项 ；
     * @param idList : Array 被删除的选项的id列表
     */
    deleteOptionForIdList(idList){
        this.options.forEach(function(option, index, arr){
            if (idList.includes(option.id)){
                arr.splice(index,1);
            }
        });
    }



    /**
     * 获得数组 questionList 内所有问题的id
     * 
     * @param questionList : [ChoiceQuestion] 问题的数组
     * @returns Array   questionList内所有问题的id
     */
    _getOptionIds(optionList) {
        return optionList.map(function (option) {
            return option.id;
        });
    }


       

}









/***
 * 问题列表
 */
export class ChoiceQuestionList extends Array {

    /* 
    @property @计算 @只读 passConditionOfQuestions : [ChoiceQuestion]   获得符合约束条件的所有题目的列表
    */
    get passConditionOfQuestions() {
        return this.filter(function (question, index) {
            return question.testAllCondition();
        });
    }


    /* 
    @property @计算 @只读 passConditionOfQuestionIds : Array   获得符合约束条件的所有题目的id列表
    */
    get passConditionOfQuestionIds() {
        return this._getQuestionIds(this.passConditionOfQuestions);
    }


    /* 
    @property @计算 @只读 notPassConditionOfQuestions : [ChoiceQuestion]   获得不符合约束条件的所有题目的列表
    */
    get notPassConditionOfQuestions() {
        return this.filter(function (question, index) {
            return !(question.testAllCondition());
        });
    }




    /* 
    @property @计算 @只读 notPassConditionOfQuestionIds : Array   获得不符合约束条件的所有题目的id列表
    */
    get notPassConditionOfQuestionIds() {
        return this._getQuestionIds(this.notPassConditionOfQuestions);
    }




    /* 
    @property @计算 @只读 answerRightQuestions : [ChoiceQuestion]   获得回答正确的题目的列表
    */
    get answerRightQuestions() {
        return this.filter(function (question) {
            return question.testAnswer();
        });
    }

    /* 
    @property @计算 @只读 answerRightQuestionIds : Array   获得回答正确的题目的id
    */
    get answerRightQuestionIds() {
        return this._getQuestionIds(this.answerRightQuestions);
    }


    /* 
    @property @计算 @只读 answerWrongQuestions : [ChoiceQuestion]   获得回答错误的题目的列表
    */
    get answerWrongQuestions() {
        return this.filter(function (question) {
            return !(question.testAnswer());
        });
    }



    /* 
    @property @计算 @只读 answerWrongQuestionIds : Array   获得回答错误的题目的id
    */
    get answerWrongQuestionIds() {
        return this._getQuestionIds(this.answerWrongQuestions);
    }




    
    /* 
    @property @计算 @只读 totalScore : number   所有题目的得分总和
    */
    get totalScore(){
        return this.reduce(function(total, currentQuestion){
            return total + currentQuestion.score;
        }, 0);
    }



    /**
     * 获得数组 questionList 内所有问题的id
     * 
     * @param questionList : [ChoiceQuestion] 问题的数组
     * @returns Array   questionList内所有问题的id
     */
    _getQuestionIds(questionList) {
        return questionList.map(function (question) {
            return question.id;
        });
    }



    //测试是否每一个题目都符合约束
    testEveryAccordCondition() {
        return this.every(function (question, index) {
            return question.testAllCondition();
        });
    }


    //测试是否有部分题目符合约束
    testSomeAccordCondition() {
        return this.some(function (question, index) {
            return question.testAllCondition();
        });
    }


    //测试是否每个题目都回答正确
    testEveryIsRight() {
        return this.every(function (question) {
            return question.testAnswer();
        });
    }


    //测试是否部分题目回答正确
    testSomeIsRight() {
        return this.some(function (question) {
            return question.testAnswer();
        });
    }




    /**
     * 取消所有题目的选中
     */
    deselectAll(){
        this.forEach(function(question){
            question.deselectAll();
        });
    }


    /**
     * 重围所有题目的选中，重置后每个题目只选中默认选中的选项
     */
    resetSelect(){
        this.forEach(function(question){
            question.resetSelect();
        });
    }













    /**
     * 返回 id 为 questionID 的 选择题 在 选择题组 中的索引；如果没有符合条件的元素返回 -1
     * @param questionID : any 被查找的选择题的id
     */
    findIndexForId(questionID){
        return this.findIndex(function(question){
            return question.id === questionID;
        });
    }


    /**
     * 返回 id 为 questionID 的 选择题；如果没有符合条件的元素返回 undefined
     * @param questionID : any 被查找的选择题的id
     */
    findQuestionForId(questionID){
        return this.find(function(question){
            return question.id === questionID;
        });
    }



    /**
     * 返回 idList 中的 id 对应的 选择题 在 选择题组 中的索引的数组；
     * @param idList : Array 被查找的选择题的id列表
     */
    findIndexListForIdList(idList){
        let questionList = this.findQuestionListForIdList(idList);
        return this._getQuestionIds(questionList);
    }


    /**
     * 返回 idList 中的 id 对应的 选择题 的数组；
     * @param idList : Array 被查找的选择题的id列表
     */
    findQuestionListForIdList(idList){
        return this.filter(function(question){
            return idList.includes(question.id);
        });
    }


    /**
     * 删除 id 为 questionID 的 选择题；
     * @param questionID : any 被删除的选择题的id
     */
    deleteQuestionForId(questionID){
        this.forEach(function(question, index, arr){
            if (question.id === questionID){
                arr.splice(index,1);
            }
        });
    }



    /**
     * 删除 idList 中指定的所有选择题 ；
     * @param idList : Array 被删除的选择题的id列表
     */
    deleteQuestionForIdList(idList){
        this.forEach(function(question, index, arr){
            if (idList.includes(question.id)){
                arr.splice(index,1);
            }
        });
    }
       







}
